#include <iostream>
#include <chrono>
#include "utils/kmp.h"
#include "utils/buffer.h"
#include "utils/queue_thread.h"
#include "utils/runnable_thread.h"
#include "utils/tcpserver.h"
#include "sources/h264_source.h"
#include "rtsp.h"
#include "h264_file.cpp"

using namespace std;
using namespace VLRTSP;

void test_tcpserver() {
	TCPServer server(10099);
	server.setServerStartCallback([=](){
		cout << "Server Start \n";
	});
	server.setServerDoneCallback([=](){
		cout << "Server Done \n";
	});
	server.setRecvSocketCallback([=](std::shared_ptr<TCPSocket> socket) {
		cout << "收到 Socket \n";
		socket.get()->close();
	});
	cout << "启动服务器 \n";
	server.start();
	cout << "开始操作 \n";
	bool isRunning = true;
	while(isRunning) {
		char c = getchar();
		switch(c) {
			case 'q':
				isRunning = false;
				server.destroy();
			break;
		}
	}
	cout << "关闭服务器操作 \n";
	std::this_thread::sleep_for(std::chrono::minutes(5));
	return;
}


void test_rtsp_thread (RTSPServer* server) {
	H264File h264_file;

	if(!h264_file.Open("/Users/cimzzz/Documents/CProjects/rtsp-server/src/example/test.h264")) {
		VL_PRINT("open file failed")
		return;
	}
	std::unique_ptr<uint8_t> frame_buf(new uint8_t[2000000]);

	std::string sessionId("live");
	while(1) {
		bool end_of_frame = false;
		int frame_size = h264_file.ReadFrame((char*)frame_buf.get(), 2000000, &end_of_frame);
		if(frame_size > 0) {
			Buffer* buffer = new Buffer(frame_size);
			buffer->appendBuffer(frame_buf.get(), 0, frame_size);
			auto time_point = chrono::time_point_cast<chrono::microseconds>(chrono::steady_clock::now());
			uint32_t time = (uint32_t)((time_point.time_since_epoch().count() + 500) / 1000 * 90 );
			server->pushMediaData(sessionId, 0, new MediaSourceData(
				buffer,
				time
			));
		}
		else {
			break;
		}
		std::this_thread::sleep_for(std::chrono::milliseconds(40));
	}
}

void test_rtsp() {
	RTSPServer* server = new RTSPServer(10099, [=](RTSPServer::RTSPServerStatus status, std::shared_ptr<std::string> message) {
		auto msgPtr = message.get();
		cout << "服务器状态变更: " << status;
		if(msgPtr != nullptr) {
			cout << ", message: " << *msgPtr;
		}
		cout << " . \n";
	});
	MediaSession* session = new MediaSession("live");
	H264Source* source = new H264Source();
	session->addMediaSource(source);
	server->addMediaSession(session);
	server->start();

	bool isRunning = true;
	while(isRunning) {
		char c = getchar();
		switch(c) {
			case 's': {
				std::thread startSS(test_rtsp_thread, server);
				startSS.detach();
				break;
			}
			case 'q':
				isRunning = false;
				server->destroy();
			break;
		}
	}
	cout << "关闭服务器操作 \n";
	delete server;
	cout << "已关闭服务器 \n";
}


void test_queue() {
	QueueThread<int> queueThread([=] (std::shared_ptr<int> data) {
		cout << "queue: " << *data.get() << ". \n";
	});
	queueThread.start();
	int count = 0;
	queueThread.addProducer([&](std::shared_ptr<int>& ptr) {
		std::this_thread::sleep_for(std::chrono::seconds(1));
		ptr.reset(new int(count ++));
		return true;
	});
	std::this_thread::sleep_for(std::chrono::seconds(8));
	cout << "准备关闭 QueueThread \n";
	queueThread.destroy();
	cout << "QueueThread 已经关闭 \n";
	std::this_thread::sleep_for(std::chrono::minutes(5));
}


void print_buffer(Buffer* buffer) {
	cout << "Buffer(length: ";
	uint32_t i = 0;
	bool isFirst = true;
	uint32_t length = buffer->getBufferLength();
	cout << length << ")[";
	for(uint8_t* iter = buffer->getBuffer() ; i < length ; i ++, iter ++ ) {
		if(isFirst) {
			isFirst = false;
		} else {
			cout << ", ";
		}
		cout << (uint32_t)(*iter);
	}

	cout << "]\n";
}

void test_buffer() {
	Buffer buffer;
	buffer.appendByte(0);
	buffer.appendByte(1);
	buffer.appendByte(2);
	buffer.appendByte(3);
	Buffer buffer2;
	buffer2.appendByte(10);
	buffer2.appendByte(11);
	buffer2.appendByte(12);
	buffer2.appendByte(13);
	buffer.insertBuffer(6, &buffer2);
	print_buffer(&buffer);
}

void test_kmp() {
	// char * pat = "aaab";
	// KMP kmp((uint8_t*)pat, 4);
	KMP kmp("aaabaaab");
	const char * txt = "aaabaaab";
	cout << "find: " << kmp.matchAfter((uint8_t*)txt, strlen(txt)) << " .\n";
}

void test_runnable_thread(int number) {
	RunnableThread thread([=]{
		VL_PRINT("hello world %d .\n", number)
	});
}

class A {

};

void test_ptr() {
	std::shared_ptr<void> ptr(new A);
	std::shared_ptr<A> ptr2(std::static_pointer_cast<A>(ptr));
	cout << "ptr count: " << ptr.use_count() << " .\n";
	cout << "ptr2 count: " << ptr2.use_count() << " .\n";
}

int main() {
	test_rtsp();
	// test_buffer();
	std::this_thread::sleep_for(std::chrono::minutes(5));
	return 0;
}